﻿#region "Copyright (C) Lenny Granovsky. 2005-2012"
//This program is free software distribute under the terms of the GNU General Public License as published by
//the Free Software Foundation. Please read AssemblyInfo.cs file for more information.
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Web.Enhancements.Rest
{
    /// <summary>
    /// Represents an attribute that is used to provide additional reading and conversion instructions for one of method parameters to a REST-service framework. 
    /// This information is required when parameter data should be loaded directly from the request input stream (HTTP message body).
    /// </summary>
    [Serializable()]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class HttpBodyParameterAttribute : Attribute
    {
        /// <summary>
        /// Gets or sets the parameter name. 
        /// </summary>
        public string ParameterName { get; set; }
        /// <summary>
        /// Gets or sets the parameter conversion hint that framework uses to read the data. 
        /// </summary>
        public ParameterConversionHint ConversionHint { get; set; }
        /// <summary>
        /// Gets or sets additional conversion instruction to use custom deserialization process in case the data converted as JSON. 
        /// </summary>
        public bool UseCustomJsonDeserialiser { get; set; }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public HttpBodyParameterAttribute()
            : base()
        {
            this.ConversionHint = ParameterConversionHint.Default;
            this.ParameterName = "";
        }
    }

    /// <summary>
    /// Represents a class that is used to provide additional reading and conversion instructions for one of method parameters to a REST-service framework. 
    /// This information is required when parameter data should be loaded directly from the request input stream (HTTP message body).
    /// </summary>
    internal class HttpBodyParameterInstructions
    {
        /// <summary>
        /// Gets or sets the parameter name. 
        /// </summary>
        public string ParameterName { get; set; }
        /// <summary>
        /// Gets or sets the parameter conversion hint that framework uses to read the data. 
        /// </summary>
        public ParameterConversionHint ConversionHint { get; set; }
        /// <summary>
        /// Gets boolean value whether one of parameters data should be loaded directly from the request input stream (HTTP message body).
        /// </summary>
        public bool HasHttpBodyParameterInstructions
        {
            get
            {
                return this.ParameterName.Length > 0;
            }
        }
        /// <summary>
        /// Gets or sets additional conversion instruction to use custom deserialization process in case the data converted as JSON. 
        /// </summary>
        public bool UseCustomJsonDeserialiser { get; set; }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public HttpBodyParameterInstructions()
            : base()
        {
            this.ConversionHint = ParameterConversionHint.Default;
            this.ParameterName = "";
        }
    }

    internal class HttpBodyParameterContext : HttpBodyParameterInstructions
    {
        /// <summary>
        /// Gets or sets the data stream came with request. 
        /// </summary>
        public Stream InputStream { get; set; }
        /// <summary>
        /// Gets or sets the content type for the data in the stream. 
        /// </summary>
        public string ContentType { get; set; }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public HttpBodyParameterContext()
            : base()
        {
            this.ContentType = "application/x-www-form-urlencoded";
        }
    }

    /// <summary>
    /// Enumeration provides conversion instructions for one of method parameters to a REST-service framework. 
    /// This information is required when parameter data should be loaded directly from the request input stream (HTTP message body).
    /// </summary>
    public enum ParameterConversionHint
    {
        /// <summary>
        /// Internal logic is used for conversion.
        /// </summary>
        Default,
        /// <summary>
        /// The XML deserialization is enforced.
        /// </summary>
        Xml,
        /// <summary>
        /// The JSON deserialization is enforced.
        /// </summary>
        Json,
        /// <summary>
        /// The JSON deserialization using data contract is enforced.
        /// </summary>
        JsonContract,
        /// <summary>
        /// The data is treated as plain text. In this case the parameter type should be string.
        /// </summary>
        Text,
        /// <summary>
        /// The data is treated as binary. In this case the parameter type should be a byte array.
        /// </summary>
        Binary,
        /// <summary>
        /// The XML or JSON deserialization is enforced based on content type setting. 
        /// The XML takes presidency if content type has no explicit information.
        /// </summary>
        XmlOrJson,
        /// <summary>
        /// The JSON or XML deserialization is enforced based on content type setting. 
        /// The JSON takes presidency if content type has no explicit information.
        /// </summary>
        JsonOrXml,
        /// <summary>
        /// The XML or JSON using data contract deserialization is enforced based on content type setting. 
        /// The XML takes presidency if content type has no explicit information.
        /// </summary>
        XmlOrJsonContract,
        /// <summary>
        /// The JSON or XML using data contract deserialization is enforced based on content type setting. 
        /// The JSON takes presidency if content type has no explicit information.
        /// </summary>
        JsonContractOrXml,
        /// <summary>
        /// The Form or Query String variables will be used to set properties within complex data types. 
        /// The PropertyWebBindingAttribute can be used to set the mapping between form variable names and properties.
        /// </summary>
        FormOrQueryVars
    }
}
